/*
 * @Date: 2023-02-16 16:10:00
 * @LastEditors: Zireael 1193875164@qq.com
 * @LastEditTime: 2023-04-12 16:48:30
 * @FilePath: \A19\frontend\src\utils\RTCConnection.ts
 */
import mitt from "@/mitt";
import { MsgRTCConn } from "@/shared/protocols/AMessages/RTC/MsgRTCConn";
import { ServiceType } from "@/shared/protocols/serviceProto";
import { tr } from "element-plus/es/locale";
import { WsClient } from "tsrpc-browser";
import { MsgLiveConn } from '../shared/protocols/AMessages/Live/MsgLiveConn';

export class RTCConnection {
  peerConnection: RTCPeerConnection;
  client: WsClient<ServiceType>;
  target: string | undefined;
  origin: string;
  streams: readonly MediaStream[];
  type: "test" | "live";
  typeId:string

  videoProvider:RTCRtpSender | undefined
  audioProvider: RTCRtpSender | undefined
  screenAudioProvider: RTCRtpSender | undefined

  constructor(
    client: WsClient<ServiceType>,
    origin: string,
    type: "test" | "live",
    typeId:string,
  ) {
    this.type = type;
    this.typeId = typeId
    this.target = undefined;
    this.origin = origin;
    this.streams = new Array();
    this.client = client;
    this.peerConnection = new RTCPeerConnection({
      iceServers: [
        // {
        //   urls: "stun:stun.stunprotocol.org",
        // },
        // {
        //   urls:'turn:43.139.162.208:3478',
        //   username:'test',
        //   credential:'123456',
        // }
      ],
    });
    this.videoProvider = undefined
    this.audioProvider = undefined

    this.peerConnection.onnegotiationneeded = this.negotiationneeded;
    this.peerConnection.onicecandidate = this.icecandidate;
    this.peerConnection.ontrack = this.track;
    this.peerConnection.oniceconnectionstatechange = ()=>{
      console.log(this.peerConnection.iceConnectionState);
    }
    this.peerConnection.onsignalingstatechange = () =>{
      console.log(this.peerConnection.signalingState)
    }
  }

  //发送方
  negotiationneeded = async () => {
    console.log("need negotiation");
    // console.log(this.target);
    
    try {
      const offer = await this.peerConnection.createOffer();
      await this.peerConnection.setLocalDescription(offer);
      if (this.type === "test") {
        //发送sdp negotiate
        this.client.sendMsg("AMessages/RTC/RTCConn", {
          type: "video-offer",
          sdp: this.peerConnection.localDescription,
          testId: this.typeId,
          target: this.target,
          origin: this.origin,
        });
      } else {
        //发送sdp negotiate
        this.client.sendMsg('AMessages/Live/LiveConn',{
          type:"video-offer",
          sdp:this.peerConnection.localDescription,
          courseId: this.typeId,
          target:this.target as string,
          origin:this.origin
        })
      }
    } catch (error) {
      this.errorHandler(error as Error);
    }
  };
  //发送方接收到answer
  handleVideoAnswer(msg: MsgRTCConn | MsgLiveConn) {
    console.log("answer received,from ", msg.origin);
    // this.target = msg.target as string
    const desc = new RTCSessionDescription(msg.sdp);
    this.peerConnection.setRemoteDescription(desc);
  }

  //接收方
  async handleVideoOffer(msg: MsgRTCConn | MsgLiveConn) {
    // console.log(msg.target);
    try {
      this.target = msg.origin as string;
      const desc = new RTCSessionDescription(msg.sdp);
      await this.peerConnection.setRemoteDescription(desc);
      // const localStream = await navigator.mediaDevices.getUserMedia({video:true,audio:false});
      // (document.getElementById('lo_video') as HTMLVideoElement).srcObject = localStream
      // localStream.getTracks().forEach(track =>{
      //   this.peerConnection.addTrack(track,localStream)
      // })
      const answer = await this.peerConnection.createAnswer();
      await this.peerConnection.setLocalDescription(answer);
      // console.log(this.peerConnection);
      //发送sdp negotiate
      if(this.type === 'test'){
        this.client.sendMsg("AMessages/RTC/RTCConn", {
          type: "video-answer",
          sdp: this.peerConnection.localDescription,
          testId:this.typeId,
          target: this.target,
          origin: this.origin,
        });
      }
      else{
        this.client.sendMsg('AMessages/Live/LiveConn',{
          type:'video-answer',
          sdp:this.peerConnection.localDescription,
          courseId:this.typeId,
          target:this.target as string,
          origin:this.origin
        })
      }
    } catch (error) {
      this.errorHandler(error as Error);
    }
  }
  //接收方拿到轨道as
  track = (event: RTCTrackEvent) => {
    console.log("track received");
    console.log(event.streams);
    console.log(event.streams[0].getTracks());
    event.streams[0].getTracks().forEach(stream =>{
      console.log(stream.getSettings());
    })

    // const video = document.getElementById('video') as HTMLVideoElement
    // video.srcObject = event.streams[0]
    // this.streams.forEach(stream =>{
    //   stream.getTracks().forEach(track =>{
    //     track.stop()
    //   })
    // })

    this.streams = event.streams;
    mitt.emit("trackReady", this.target);
  };

  //候选交换
  icecandidate = (event: RTCPeerConnectionIceEvent) => {
    // console.log('onicecandidate');
    if (event.candidate) {
      if (this.type === "test") {
        //发送候选
        this.client.sendMsg("AMessages/RTC/RTCConn", {
          type: "new-ice-candidate",
          testId:this.typeId,
          target: this.target,
          candidate: event.candidate,
          origin: this.origin,
        });
      }
      else{
        //发送候选
        this.client.sendMsg('AMessages/Live/LiveConn', {
          type: "new-ice-candidate",
          courseId: this.typeId,
          target: this.target as string,
          candidate: event.candidate,
          origin: this.origin,
        });
      }
    }
  };

  //候选到达
  async addCandidate(msg: MsgRTCConn | MsgLiveConn) {
    console.log("add candidate");
    try {
      await this.peerConnection.addIceCandidate(msg.candidate);
    } catch (error) {
      this.errorHandler(error as Error);
    }
  }

  closeConnection() {
    this.peerConnection.close()
    this.streams.forEach(stream => {
      stream.getTracks().forEach(track => track.stop())
    })
  }
  errorHandler(err: Error) {
    console.log(err);
  }
}
